using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using BitMango.Diagnostics;
using UnityEngine;

namespace BitMango.MultiPlayer
{
	public class MatchImplBase
	{
		public static MatchImplBase.STATE State
		{
			get
			{
				return MatchImplBase.state;
			}
			private set
			{
				UnityEngine.Debug.Log(string.Concat(new object[]
				{
					"Match101.Set state called : ",
					MatchImplBase.state,
					"->",
					value
				}));
				MatchImplBase.state = value;
			}
		}

		public bool IsOpen
		{
			get
			{
				return MatchImplBase.state >= MatchImplBase.STATE.OPENED;
			}
		}

		public void Open(int _gameVariant, Action<bool> callback)
		{
			Debugger.Assert(MatchImplBase.state == MatchImplBase.STATE.NONE, "Match101.Open state:" + MatchImplBase.state);
			Debugger.Assert(callback != null);
			this.openCallback = callback;
			MatchImplBase.State = MatchImplBase.STATE.OPEN;
			this.OpenImpl(_gameVariant, callback);
		}

		protected virtual void OpenImpl(int _gameVariant, Action<bool> callback)
		{
			Debugger.Assert(false, "MatchImplBase.OpenImpl called");
		}

		protected void OnOpenInternal(bool success)
		{
			Debugger.Assert(MatchImplBase.state == MatchImplBase.STATE.OPEN, "Match101.OnOpenInternal state: " + MatchImplBase.state);
			Debugger.Assert(this.openCallback != null, "MatchImplBase.OnOpenInternal : openCallback is null");
			if (MatchImplBase.State != MatchImplBase.STATE.OPENED)
			{
				MatchImplBase.State = ((!success) ? MatchImplBase.STATE.NONE : MatchImplBase.STATE.OPENED);
			}
			Platform.SafeCallback<bool>(this.openCallback, success);
			this.openCallback = null;
		}

		public void Close(bool opponent)
		{
			Debugger.Log("Match101.Close called " + MatchImplBase.state);
			if (MatchImplBase.state != MatchImplBase.STATE.NONE)
			{
				MatchImplBase.state = MatchImplBase.STATE.NONE;
				Platform.SafeCallback<bool>(this.openCallback, false);
				this.openCallback = null;
				this.readyCallback = null;
				this.rematchCallback = null;
				this.OnClose(opponent);
				this.CloseImpl(opponent);
			}
		}

		protected virtual void CloseImpl(bool opponent)
		{
			Debugger.Assert(false, "MatchImplBase.CloseImpl called");
		}

		public void Ready(object userData, object pkt, Action<Match.User, object> callback)
		{
			Debugger.Assert(MatchImplBase.state > MatchImplBase.STATE.OPEN, "Match101.Ready state:" + MatchImplBase.state);
			Debugger.Log("Match101.Ready called " + MatchImplBase.state);
			Match.Me.userData = userData;
			Match.Me.ready = true;
			this.SendInternal(1, new MatchImplBase.ReadyPacket
			{
				userData = userData,
				message = pkt
			});
			MatchImplBase.State = MatchImplBase.STATE.READY;
			this.readyCallback = callback;
			if (Match.Opponent.ready)
			{
				Debugger.Assert(this.readyCallback != null);
				Debugger.Assert(this.opponentReadyMessage != null);
				MatchImplBase.State = MatchImplBase.STATE.PLAY;
				TaskManager.DoNextFrame(delegate
				{
					this.readyCallback(Match.Opponent, this.opponentReadyMessage);
					this.readyCallback = null;
				}, 1);
			}
		}

		public void Send(object msg)
		{
			this.SendInternal(2, msg);
		}

		private void SendInternal(byte cmd, object msg)
		{
			Debugger.Log(string.Concat(new object[]
			{
				"Match101.Send : cmd(",
				cmd,
				"), msg type",
				msg.GetType().FullName
			}));
			this.SendInternalImpl(cmd, msg);
		}

		protected virtual void SendInternalImpl(byte cmd, object msg)
		{
			Debugger.Assert(false, "MatchImplBase.SendInternalImpl called");
		}

		public void Fin(object pkt)
		{
			Debugger.Assert(MatchImplBase.state == MatchImplBase.STATE.PLAY, "Match101.Fin state is not PLAY : " + MatchImplBase.state);
			Debugger.Log(string.Concat(new object[]
			{
				"Match101.Fin isMaster(",
				Match.IsMaster,
				"), pkt(",
				pkt.GetType().FullName,
				")"
			}));
			if (!Match.IsMaster)
			{
				this.SendInternal(4, pkt);
			}
			else
			{
				this.SendInternal(3, pkt);
				this.FinInternal(pkt);
			}
		}

		protected void FinInternal(object msg)
		{
			Debugger.Assert(MatchImplBase.state == MatchImplBase.STATE.PLAY, "Match101.FinInternal state is not PLAY : " + MatchImplBase.state);
			MatchImplBase.State = MatchImplBase.STATE.FIN;
			if (this.OnFin != null)
			{
				this.OnFin(msg);
			}
		}

		public void ReMatch(bool answer, Action<bool> callback)
		{
			Debugger.Assert(MatchImplBase.state == MatchImplBase.STATE.FIN);
			Debugger.Log("Match101.ReMatch , state " + MatchImplBase.state);
			MatchImplBase.State = MatchImplBase.STATE.REMATCH;
			Match.Me.rematchAnswer = ((!answer) ? 2 : 1);
			this.rematchCallback = callback;
			this.SendInternal(5, Match.Me.rematchAnswer);
			if (Match.Opponent.rematchAnswer == 1 || Match.Opponent.rematchAnswer == 2)
			{
				bool param = Match.Me.rematchAnswer == 1 && Match.Opponent.rematchAnswer == 1;
				MatchImplBase.State = MatchImplBase.STATE.OPENED;
				Match.InitUser();
				Platform.SafeCallback<bool>(this.rematchCallback, param);
				this.rematchCallback = null;
			}
		}

		protected void OnRecvInternal(byte cmd, object msg)
		{
			Debugger.Log("Match101.OnRecvInternal : " + (PACKET)cmd);
			switch (cmd)
			{
			case 1:
			{
				MatchImplBase.ReadyPacket readyPacket = msg as MatchImplBase.ReadyPacket;
				Debugger.Assert(readyPacket != null, "OnRealTimeMessageReceived.packet is null:" + msg.GetType().FullName);
				Debugger.Assert(Match.Me != null, "OnRealTimeMessageReceived.PACKET.READY me null");
				Debugger.Assert(Match.Opponent != null, "OnRealTimeMessageReceived.PACKET.READY opponent null");
				Debugger.Assert(MatchImplBase.State == MatchImplBase.STATE.OPENED || MatchImplBase.State == MatchImplBase.STATE.READY, "OnRealTimeMessageReceived opened nor ready" + MatchImplBase.State);
				Match.Opponent.ready = true;
				Match.Opponent.userData = readyPacket.userData;
				this.opponentReadyMessage = readyPacket.message;
				if (Match.Me.ready)
				{
					Debugger.Assert(this.readyCallback != null, "OnRealTimeMessageReceived.readycallback is null");
					MatchImplBase.State = MatchImplBase.STATE.PLAY;
					this.readyCallback(Match.Opponent, readyPacket.message);
					this.readyCallback = null;
				}
				break;
			}
			case 2:
				this.OnRecv(msg);
				break;
			case 3:
				Debugger.Assert(!Match.IsMaster);
				this.FinInternal(msg);
				break;
			case 4:
				Debugger.Assert(Match.IsMaster);
				if (MatchImplBase.State == MatchImplBase.STATE.PLAY)
				{
					this.Fin(msg);
				}
				else
				{
					UnityEngine.Debug.LogWarning("Match101.OnRealTimeMessageReceived : packet.reqfin dupplicated" + MatchImplBase.State);
				}
				break;
			case 5:
			{
				Debugger.Assert(MatchImplBase.State == MatchImplBase.STATE.FIN || MatchImplBase.State == MatchImplBase.STATE.REMATCH);
				int num = (int)msg;
				Debugger.Assert(num != 0, "MatchImplBase.OnRecv[Packet.REMATCH] Recieve message must 1 or 2,msg is" + num);
				Match.Opponent.rematchAnswer = num;
				if (Match.Me.rematchAnswer != 0)
				{
					bool param = Match.Me.rematchAnswer == 1 && Match.Opponent.rematchAnswer == 1;
					MatchImplBase.State = MatchImplBase.STATE.OPENED;
					Match.InitUser();
					Platform.SafeCallback<bool>(this.rematchCallback, param);
					this.rematchCallback = null;
				}
				break;
			}
			default:
				Debugger.Assert(false, "Match101.OnReceive Unknown command : " + cmd);
				break;
			}
		}

		public static byte[] ObjectToByteArray(byte cmd, object obj)
		{
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			byte[] result;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				memoryStream.WriteByte(cmd);
				binaryFormatter.Serialize(memoryStream, obj);
				result = memoryStream.ToArray();
			}
			return result;
		}

		public static object ByteArrayToObject(byte[] arrBytes, int offset)
		{
			object result;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				BinaryFormatter binaryFormatter = new BinaryFormatter();
				memoryStream.Write(arrBytes, offset, arrBytes.Length - offset);
				memoryStream.Seek(0L, SeekOrigin.Begin);
				object obj = binaryFormatter.Deserialize(memoryStream);
				result = obj;
			}
			return result;
		}

		private static MatchImplBase.STATE state;

		protected object opponentReadyMessage;

		public Action<object> OnRecv;

		public Action<object> OnFin;

		public Action<bool> OnClose;

		protected Action<bool> openCallback;

		protected Action<Match.User, object> readyCallback;

		protected Action<bool> rematchCallback;

		[Serializable]
		public class ReadyPacket
		{
			public object userData;

			public object message;
		}

		public enum STATE
		{
			NONE,
			OPEN,
			OPENED,
			READY,
			PLAY,
			FIN,
			REMATCH
		}
	}
}
